﻿#region Header
// Copyright 2007-2011, Jerónimo Milea
// 
// This file is part of NetJsWire.
// 
//     NetJsWire is free software: you can redistribute it and/or modify
//     it under the terms of the GNU General Public License as published by
//     the Free Software Foundation, either version 3 of the License, or
//     (at your option) any later version.
// 
//     NetJsWire is distributed in the hope that it will be useful,
//     but WITHOUT ANY WARRANTY; without even the implied warranty of
//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//     GNU General Public License for more details.
// 
//     You should have received a copy of the GNU General Public License
//     along with NetJsWire.  If not, see <http://www.gnu.org/licenses/>.
#endregion

using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
using System.Web;
using NetJsWire.Direct.attributes;
using Newtonsoft.Json.Linq;

namespace NetJsWire.Direct
{
    /// <summary>
    ///   Class for processing Ext Direct requests.
    /// </summary>
    public class DirectProcessor
    {
        /// <summary>
        ///   Processes an incoming request.
        /// </summary>
        /// <param name = "provider">The provider that triggered the request.</param>
        /// <param name = "httpContext">The http information.</param>
        /// <returns>The result from the client method.</returns>
        public static DirectExecution Execute( DirectProvider provider, HttpContext httpContext )
        {

            var directExecution = new DirectExecution();

            var httpRequest = httpContext.Request;
            // parse the a list of requests from the httpRequest
            var requests = ParseRequest( httpRequest );
            var responses = new List<DirectResponse>();

            // after parsing was successfull Proccess the list of requests
            foreach ( var request in requests )
            {
                // try to find the method in the provider 
                var directMethod = provider.GetDirectMethod( request );
                DirectResponse response;


                // try to Invoke the Method and serialize the Data
                try
                {
                    var result = directMethod.invoke( request, httpContext );


                    // Handle as Poll?
                    if ( directMethod.OutputHandling == OutputHandling.Poll )
                    {

                        response = new DirectResponse( request, "{success:true}", directMethod.OutputHandling );
                        responses.Add( response );

                        if ( result is List<DirectEvent> )
                        {
                            foreach ( var currEvent in ( List<DirectEvent> ) result )
                            {
                                response = new DirectResponse( currEvent );

                                responses.Add( response );
                            }
                        }
                        else
                        {
                            throw new Exception( "A Method with outputhandling Poll has to return a List<DirectEvent>" );
                        }

                    }
                    else
                    {
                        response = new DirectResponse( request, result, directMethod.OutputHandling );
                        responses.Add( response );

                    }
                }
                catch ( TargetInvocationException e )
                {
                    response = new DirectResponse( request, e.InnerException );
                    responses.Add( response );
                }



            }

            var output = "[";

            var i3 = 1;
            foreach ( var response in responses )
            {
                if ( response.Type == "exception" )
                {
                    directExecution.containsErrors = true;
                }
                output += response.toJson();
                if ( responses.Count > i3 )
                {
                    output += ",";
                }
                i3++;
            }

            output += "]";
            directExecution.jsonResponse = output;

            return directExecution;

        }

        internal static List<DirectRequest> ParseRequest( HttpRequest httpRequest )
        {
            // TODO Throw parse Exception

            var proccessList = new List<DirectRequest>();
            if ( !String.IsNullOrEmpty( httpRequest[ DirectRequest.RequestFormAction ] ) )
            {
                var request = new DirectRequest();
                request.Action = httpRequest[ DirectRequest.RequestFormAction ] ?? string.Empty;
                request.Method = httpRequest[ DirectRequest.RequestFormMethod ] ?? string.Empty;
                request.Type = httpRequest[ DirectRequest.RequestFormType ] ?? string.Empty;
                request.IsUpload = Convert.ToBoolean( httpRequest[ DirectRequest.RequestFormUpload ] );
                request.TransactionId = Convert.ToInt32( httpRequest[ DirectRequest.RequestFormTransactionId ] );
                request.Data = null;
                request.HttpRequest = httpRequest;
                proccessList.Add( request );
            }
            else
            {
                var encoding = new UTF8Encoding();
                var json = encoding.GetString( httpRequest.BinaryRead( httpRequest.TotalBytes ) );


                JArray directRequests;
                try
                {
                    directRequests = !json.StartsWith( "[" ) ? JArray.Parse( "[" + json + "]" ) : JArray.Parse( json );
                }
                catch ( Exception e )
                {
                    directRequests = JArray.Parse( "[" + json + "]" );
                }

                foreach ( JObject dreq in directRequests )
                {
                    proccessList.Add( new DirectRequest( dreq ) );
                }

            }
            return proccessList;
        }


    }
}
